#!/usr/bin/env node
'use strict';

/**
 *  To serve https in development, your shell startup script (e.g., ~/.bashrc)
 *  needs to include lines like this that point to the paths for your self-signed
 *  certificate and key files:
 *
 *  export LOCALHOST_SSL_CERT="$HOME/path/to/your/cert.pem"
 *  export LOCALHOST_SSL_KEY="$HOME/path/to/your/key.pem"
 *
 */
const key_path = process.env.LOCALHOST_SSL_KEY;
const cert_path = process.env.LOCALHOST_SSL_CERT;

const {app, io, public_dir} = require('../server');
const debug = require('debug')(process.env.DEBUG);
const fs = require('fs');
const ifaces = require('os').networkInterfaces();

const {server, protocol} = selectServer(key_path, cert_path);

/**
 *  Use the PORT environment variable or default to 3000.
 */

const port = process.env.PORT ?? '3000';
app.set('port', port);

/**
 *  Attach socket.io to the web server.
 */
io.attach(server);

/**
 *  Listen on provided port, on all network interfaces.
 */

server.listen(port);
server.on('error', handleError);
server.on('listening', handleListening);

/**
 *  Look for keys and set the server accordingly.
 */

function selectServer(k, c) {
  const config = {};
  if (k && c) {
    try {
      const key = fs.readFileSync(k);
      const cert = fs.readFileSync(c);
      config.protocol = 'https';
      config.server = require(config.protocol).createServer({key: key, cert: cert }, app);
    } catch(e) {
      console.error(e);
      process.exit(1);
    }
  } else {
    debug(' WARNING: Your server is using \'http\', not \'https\'.\n Some things might not work as expected.\n');
    config.protocol = 'http';
    config.server = require(config.protocol).createServer(app);
  }
  return config;
}

/**
 *  Event listener for HTTP server "error" event.
 */

function handleError(error) {
  if (error.syscall !== 'listen') {
    throw error;
  }

  switch (error.code) {
  case 'EADDRINUSE':
    console.error(`Port ${port} is already being used`);
    process.exit(1);
    break;
  case 'EACCES':
    console.error(`Port ${port} requires elevated user privileges (sudo)`);
    process.exit(1);
    break;
  default:
    throw error;
  }
}

/**
 *  Callback for server listen event
 */

function handleListening() {
  const address = server.address();
  // Inspired by https://github.com/http-party/http-server/blob/master/bin/http-server#L163
  const interfaces = [];
  Object.keys(ifaces).forEach(function(dev) {
    ifaces[dev].forEach(function(details) {
      /**
       * Node v. 18+ returns a number (4, 6) for family;
       * earlier versions returned IPv4 or IPv6. This handles
       * both cases.
       */
      if (details.family.toString().endsWith('4')) {
        interfaces.push(`-> ${protocol}://${details.address}:${address.port}/`);
      }
    });
  });
  debug(
    `  ** Serving from the ${public_dir}/ directory. **

  App available in your browser at:

    ${interfaces.join('\n    ')}

  Hold CTRL + C to stop the server.\n\n `
  );
}
